package example.demo.controller;


import example.demo.service.IKillGoodsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author xiao_rao
 * @since 2021-07-30
 */
@Slf4j
@RestController
@RequestMapping("/rao/kill-goods")
public class KillGoodsController {

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe;
    private static final long valueOffset;

    static {
        try {
            Class<Unsafe> unsafeClass = Unsafe.class;
            Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe) theUnsafe.get(null);
            valueOffset = unsafe.objectFieldOffset
                    (KillGoodsController.class.getDeclaredField("value"));
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    private volatile int value;
    final List<String> strings = Arrays.asList("喜羊羊", "懒羊羊", "沸羊羊", "美羊羊");

    // http://127.0.0.1:8080/rao/kill-goods/atomicCount 简单来说轮询算法就可以看作一个i++操作
    @RequestMapping("/atomicCount")
    public String atomicCount() {
        int val = value;
//        int count = 0;
        while (!unsafe.compareAndSwapInt(this, valueOffset, val, val + 1)) {
            //重新加载主存的值，放到当前线程的工作的内存。
            val = value;
//            if (((count++) & 31) == 0) {
//                Thread.yield();
//            }
        }
//        return "当前的value是--->" + this.value;//不能返回这个this.value，而应该返回val+1
        return "当前成功修改的value是--->" + (val + 1) + strings.get((val + 1) & 3);//而是返回这个
    }

    @Autowired
    IKillGoodsService killGoodsService;

    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByRedisSegment
     * redis写热点分离
     */
    @RequestMapping("/secondKillByRedisSegment")
    public String secondKillByRedisSegment(Integer killId) {
        boolean b = killGoodsService.redisSegment(killId);
        if (b) {
            return "秒杀-succeed";
        }
        return "秒杀-fail";
    }


    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByRedisLua
     * redis-lua脚本的原子性
     */
    @RequestMapping("/secondKillByRedisLua")
    public String secondKillByRedisLua(Integer killId) {
        boolean b = killGoodsService.redisLua(killId);
        if (b) {
            return "秒杀-succeed";
        }
        return "秒杀-fail";
    }
//todo jmeter使用 https://blog.csdn.net/lovesoo/article/details/78579547

    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByDbMultiTableSegment
     * 数据库，多张表写热点分离
     */
    @RequestMapping("/secondKillByDbMultiTableSegment")
    public String secondKillByDbMultiTableSegment(Integer killId) {
        boolean b = killGoodsService.dbMultiTableSegment(killId);
        if (b) {
            return "秒杀-succeed";
        }
        return "秒杀-fail";
    }


    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByredisLock
     * 直接使用一把锁只对应一个库存key，且一种商品只对应一个库存key
     */
    @RequestMapping("/secondKillByredisLock")
    public String secondKillByredisLock(Integer killId) {
        boolean b = killGoodsService.redisLock(killId);
        if (b) {
            log.info("秒杀-succeed");
            return "秒杀-succeed";
        }
        log.info("秒杀-fail");
        return "秒杀-fail";
    }

    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByDdbMultiRowsSegment?killId=10
     * 一张表多条记录，多次尝试知道没库存才退出
     */
    @RequestMapping("/secondKillByDdbMultiRowsSegment")
    public String secondKillByDdbMultiRowsSegment(Integer killId) {
        boolean b = killGoodsService.dbMultiRowsSegment(killId);
        if (b) {
            log.info("秒杀-succeed");
            return "秒杀-succeed";
        }
        log.info("秒杀-fail");
        return "秒杀-fail";
    }


    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByDbMultiRowsSegmentTryOne?killId=10
     * 数据库一张表多条记录写热点分离，只会随机调用一次
     */
    @RequestMapping("/secondKillByDbMultiRowsSegmentTryOne")
    public String secondKillByDbMultiRowsSegmentTryOne(Integer killId) {
        boolean b = killGoodsService.dbMultiRowsSegmentTryOne(killId);
        if (b) {
            log.info("秒杀-succeed");
            return "秒杀-succeed";
        }
        log.info("秒杀-fail");
        return "秒杀-fail";
    }

    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByDbMultiRowsSegmentTryOneCycleUse?killId=10
     * 数据库一张表多条记录写热点分离，轮询只会调用一次，
     */
    @RequestMapping("/secondKillByDbMultiRowsSegmentTryOneCycleUse")
    public String secondKillByDbMultiRowsSegmentTryOneCycleUse(Integer killId) {
        boolean b = killGoodsService.dbMultiRowsSegmentTryOneCycleUse(killId);
        if (b) {
            log.info("秒杀-succeed");
            return "秒杀-succeed";
        }
        log.info("秒杀-fail");
        return "秒杀-fail";
    }

    /**
     * http://127.0.0.1:8080/rao/kill-goods/secondKillByDB?killId=10
     * 一张表一条数据使用数据库秒杀
     */
    @RequestMapping("/secondKillByDB")
    public String secondKillByDB(Integer killId) {
        boolean b = killGoodsService.db(killId);
        if (b) {
            return "秒杀-succeed";
        }
        return "秒杀-fail";
    }

}
